#include <iostream>
#include <cstdint>
#include <functional>
#include <memory>
#include <vector>
#include <unordered_map>
#include <unistd.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;      // 定时器任务对象ID, 定时器任务必须得找得到, 在一个程序里定时器任务可能有很多
    uint32_t _timeout; // 定时任务的超时时间
    TaskFunc _task_cb; // 定时器要执行的任务
    // 用于删除TimeWheel中保存的定时器任务对象信息,定时任务释放(执行)的时候,也要清理TimeWheel中保存的定时器对象消息
    // 为什么将这个_release 设置到Timertask里面的呢,而不在TimerWheel层管理?
    // 因为这个Time Wheel不知道是否某个定时任务真的释放了,而TimerTask是最清楚的,自己真的释放掉了就会调用析构函数
    ReleaseFunc _release;
    bool _canceled; // false->代表没有取消,  true->代表取消

public:
    TimerTask(uint64_t id, uint32_t timeout, const TaskFunc &cb)
        : _id(id), _timeout(timeout), _task_cb(cb), _canceled(false) {}
    ~TimerTask()
    {
        if (_canceled == false) // 定时任务是否取消, 默认没有取消
            _task_cb();
        _release();
    }
    void SetRelease(const ReleaseFunc &cb)
    {
        _release = cb;
    }
    uint32_t DelayTime()
    {
        return _timeout;
    }
    void Cancel()
    {
        _canceled = true;
    }
};

class TimeWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    int _tick;     // 当前的秒针,走到哪里释放哪里(执行任务后释放),
    int _capacity; // 表盘的最大数量 -- 最大延迟的时间
    std::vector<std::vector<PtrTask>> _wheel;
    // 为什么不用普通指针,而是用weak_ptr,weak_ptr,不会增加引用计数的
    std::unordered_map<uint64_t, WeakTask> _timers; // 对所有的定时任务进行管理

private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

public:
    TimeWheel()
        : _tick(0), _capacity(60), _wheel(_capacity) {}

    // 添加定时任务
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        // 1.构建定时任务
        PtrTask pt(new TimerTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimer, this, id));
        // 2.将定时任务添加到_wheel中
        int i = (_tick + delay) % _capacity;
        _wheel[i].push_back(pt);
        // 3.加入到时间轮的_timers里面 /保存信息
        // std::unordered_map<uint_t, WeakTask>::iterator pos = _timers.find(id);
        auto pos = _timers.find(id);
        if (pos == _timers.end())
        {
            _timers.insert({id, WeakTask(pt)});
        }
    }
    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        // 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来，添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            // 没有找到定时任务,则没办法更新任务
            return;
        }
        PtrTask pt = it->second.lock(); // lock函数获取weak_ptr管理的对象对应的shared_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    // 取消定时任务
    void TimerCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            // 没有找到定时任务,无法取消定时任务
            return;
        }
        PtrTask pt = it->second.lock();
        if (pt)
            pt->Cancel();
    }
    // 这个函数会每秒钟执行一次，相当于秒针向后走了一步
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        // 清空指定位置的数组,就是把数组中保存的所有管理定时器的对象的PtrTask-->shared_ptr释放掉
        _wheel[_tick].clear();
    }
};

class Task
{
public:
    Task() { std::cout << "构造" << std::endl; }
    ~Task() { std::cout << "析构" << std::endl; }
};
void DelTest(Task *t)
{
    delete t;
}
int main()
{
    TimeWheel tw;

    Task *t = new Task();

    tw.TimerAdd(111, 5, std::bind(DelTest, t));

    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.TimerRefresh(888); // 刷新定时任务
        std::cout << "刷新了一下定时任务，重新需要5s中后才会销毁\n";
        tw.RunTimerTask();    // 向后移动秒针
    }

    while (1)
    {
        sleep(1);
        std::cout << "-------------------\n";
        tw.RunTimerTask(); // 向后移动秒针
    }
    return 0;
}
